package handler

import (
	"strconv"
	"trader/apps/common/resp"
	"trader/constant"
	"trader/models"

	"github.com/gin-gonic/gin"
	"xorm.io/xorm"
)

type PlanHandler struct {
	Engine *xorm.Engine
}

func NewPlanHandler(engine *xorm.Engine) *PlanHandler {
	return &PlanHandler{Engine: engine}
}

type PlanCreateRequest struct {
	StockId           int64    `json:"stockId" binding:"required"`
	Title             string   `json:"title" binding:"required,gte=1,lte=100"`
	TakeProfitPrice   float64  `json:"takeProfitPrice" binding:"required,gte=0"`
	StopLossPrice     float64  `json:"stopLossPrice" binding:"required,gte=0"`
	ValuationAnalysis []string `json:"valuationAnalysis" binding:"required"`
}

func (h PlanHandler) Create(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")

	var req PlanCreateRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		resp.FailParam(c, err)
		return
	}

	exist, _ := h.Engine.Where("trading_account_id=? and status=0 and stock_id=?", accountId, req.StockId).Exist(new(models.TransactionPlan))
	if exist {
		resp.FailParamf(c, "该账户Stock有正在进行中的计划")
		return
	}

	exist, _ = h.Engine.Where("trading_account_id=? and stock_id=? and title=?", accountId, req.StockId, req.Title).Exist(new(models.TransactionPlan))
	if exist {
		resp.FailParamf(c, "交易计划名称重复")
		return
	}

	stock := new(models.Stock)
	exist, _ = h.Engine.Where("trading_account_id=? and id=?", accountId, req.StockId).Get(stock)
	if !exist {
		resp.FailParamf(c, "Stock 不存在")
		return
	}

	newPlan := &models.TransactionPlan{
		StockId:           req.StockId,
		Code:              stock.Code,
		Name:              stock.Name,
		Title:             req.Title,
		TakeProfitPrice:   req.TakeProfitPrice,
		StopLossPrice:     req.StopLossPrice,
		ValuationAnalysis: req.ValuationAnalysis,
		TradingAccountId:  accountId,
		Status:            constant.Running,
	}

	if _, err := h.Engine.Insert(newPlan); err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OK(c, "添加成功", gin.H{"id": newPlan.Id})
}

type PlanUpdateRequest struct {
	Title             string   `json:"title" binding:"required,gte=1,lte=100"`
	TakeProfitPrice   float64  `json:"takeProfitPrice" binding:"required"`
	StopLossPrice     float64  `json:"stopLossPrice" binding:"required"`
	ValuationAnalysis []string `json:"valuationAnalysis" binding:"required"`
}

func (h PlanHandler) Update(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")
	id, err := strconv.ParseInt(c.Param("plan_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	var req PlanUpdateRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		resp.FailParam(c, err)
		return
	}

	_, err = h.Engine.Where("trading_account_id=? and id=?", accountId, id).
		Cols("title", "take_profit_price", "stop_loss_price", "valuation_analysis").
		Update(map[string]any{
			"title":              req.Title,
			"take_profit_price":  req.TakeProfitPrice,
			"stop_loss_price":    req.StopLossPrice,
			"valuation_analysis": req.ValuationAnalysis,
		})
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKWithoutData(c, "更新成功")
}

func (h PlanHandler) Delete(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")
	id, err := strconv.ParseInt(c.Param("plan_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}
	_, err = h.Engine.Where("trading_account_id=? and id=?", accountId, id).Delete(new(models.TransactionPlan))
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKWithoutData(c, "已删除")
}

func (h PlanHandler) Get(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")
	id, err := strconv.ParseInt(c.Param("plan_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	plan := new(models.TransactionPlan)
	has, err := h.Engine.Where("trading_account_id=? and id=?", accountId, id).Get(plan)
	if err != nil {
		resp.FailDB(c, err)
		return
	}
	if !has {
		resp.FailParamf(c, "计划不存在")
		return
	}

	resp.OK(c, "ok", plan)
}

func (h PlanHandler) List(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")
	stockId := c.GetInt64("stockId")

	page, err := strconv.ParseInt(c.DefaultQuery("page", "1"), 10, 64)
	if err != nil {
		page = 1
	}

	pageSize, err := strconv.ParseInt(c.DefaultQuery("page_size", "10"), 10, 64)
	if err != nil {
		pageSize = 10
	}

	key := c.Query("key")
	query := h.Engine.Where("trading_account_id = ? and stock_id=?", accountId, stockId)
	if key != "" {
		query = query.Or("code LIKE ? ", "%"+key+"%").Or("name LIKE ?", "%"+key+"%")
	}

	plans := make([]models.TransactionPlan, 0)
	total, err := query.OrderBy("-id").Limit(int(pageSize), int((page-1)*pageSize)).FindAndCount(&plans)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKPage(c, total, page, pageSize, plans)
}

type PlanSetStatusRequest struct {
	Status *int `json:"status" binding:"required,oneof=0 1"`
}

func (h PlanHandler) SetStatus(c *gin.Context) {
	accountId := c.GetInt64("tradingAccountId")
	id, err := strconv.ParseInt(c.Param("plan_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	stockId := c.GetInt64("stockId")

	var req PlanSetStatusRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		resp.FailParam(c, err)
		return
	}

	// 当反完结时，检查是否有其他进行中的
	if *req.Status == constant.Running {
		exist, _ := h.Engine.Where("trading_account_id=? and stock_id=? and id !=? and status=?", accountId, stockId, id, constant.Running).Get(new(models.TransactionPlan))
		if exist {
			resp.Failf(c, "一只Stock同时只能有一个进行中的计划")
			return
		}
	}

	_, err = h.Engine.Table(new(models.TransactionPlan)).
		Where("trading_account_id=? and id=?", accountId, id).
		Cols("status").
		Update(map[string]any{"status": req.Status})
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKWithoutData(c, "已修改")
}
